#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <malloc.h>
#include <unistd.h>
#include <fcntl.h>

#include "parser.h"
#include "debug.h"

void parse(const char *const s, struct conf_http **ret) {
  const char *pos = s;
  write(STDOUT_FILENO, s, strlen(s));
  pos = strstr(s, "http");
  char buf[128];
  sscanf(pos, "%s", buf);
  struct conf_http *http_config;
  if( strcmp("http", buf) == 0 ) {
    const char *ret_l, *ret_r;
    delimit(s, s+strlen(s), &ret_l, &ret_r);
    write(STDOUT_FILENO, ret_l, ret_r-ret_l);
    putchar('\n');
    parse_http(ret_l, ret_r, &http_config);
  }
  *ret = http_config;
}

void parse_http(const char *const bracel, const char *bracer, struct conf_http **ret)
{
  *ret = (struct conf_http *)malloc(sizeof(struct conf_http));
  const char *pos = bracel + 1;
  char buf[128];
  sscanf(pos, "%s", buf);

  (**ret).server_num = how_many_servers(bracel);

  const char *ret_l, *ret_r;
  for(int i=0; i<(**ret).server_num && pos < bracer; pos = ret_r, i++) {
    if( strcmp("server", buf) == 0) {
      delimit(pos, pos+strlen(pos), &ret_l, &ret_r);
      parse_http_server(ret_l, ret_r, &(**ret).servers[i]);
    }
  }
  // list_http(*ret);
}

void parse_http_server(const char *const bracel, const char *bracer, struct conf_http_server **ret)
{
  *ret = malloc(sizeof(struct conf_http_server));
  if(ret==NULL) {
    perror("malloc failed");
    _exit(-1);
  }
  printf("Parse HTTP server\n");
  // write(STDOUT_FILENO, bracel, bracer-bracel);
  char buf[512];
  strncpy(buf, bracel, bracer-bracel);
  buf[bracer-bracel] = '\0';

  char *server_name = (**ret).server_name;
  char *root = (**ret).location.map_to;
  strcpy((**ret).location.from, "/");

  /* linten */
  int listen = 0;
  const char *pos = strstr(buf, "listen");
  if(pos!=NULL) {
    sscanf(pos, " %*s %d", &listen);
    (**ret).listen = listen;
  }
  /* server_name */
  pos = strstr(buf, "server_name");
  if(pos!=NULL) {
    sscanf(pos, " %*s %[^;];", server_name);
  }
  /* root */
  pos = strstr(buf, "root");
  if(pos!=NULL) {
    (**ret).location.type = SERVER_ROOT;
    sscanf(pos, " %*s %[^;]", root);
  }
  // else {
  /* location */
    pos = strstr(buf, "location");
    if(pos != NULL) {
      char *p = (**ret).location.from;
      sscanf(pos, " %*s %s", (**ret).location.from);
      p[strlen(p)+1] = '\0';
      if(strlen(p)!=1) p[strlen(p)] = '/';
      pos = strstr(buf, "proxy_pass");
      if(pos!=NULL) {
        (**ret).location.type = SERVER_PROXY_PASS;
        sscanf(pos, " %*s %[^;]", (**ret).location.from);
      }
      else {
        pos = strstr(buf, "root");
        if(pos != NULL) {
          (**ret).location.type = SERVER_ROOT;
        }
      }
    }
  // }

  printf("\n");
  printf("\033[43mlisten: %d\033[0m\n", listen);
  printf("\033[43mserver_name: %s\033[0m\n", server_name);
  printf("\033[43mroot: %s\033[0m\n", root);
  printf("\n");
}


bool delimit(const char * l, const char *const r, const char **const ret_l, const char **const ret_r)
{
  l = strchr(l, '{') + 1;
  *ret_l = l;
  int left = 1;
  for(; left && l<r; ++l) {
    if(*l == '{') {
      left++;
    }
    else if(*l == '}') {
      left--;
    }
  }
  
  *ret_r = l-1;
  if(l != r) {
    return true;
  }
  else {
    *ret_l = *ret_r = NULL;
    return false;
  }
}

const char *read_line_till_semicolon(const char *s)
{
  return strchr(s, ';');
}

void simplify(char *const s)
{
  int len = strlen(s);
  for(int i=0; i<len; ++i) {
    if(s[i]=='\n' || s[i] == '\r') s[i] = ' ';
  }
}

int how_many_servers(const char *s)
{
  // TODO: Regular Expression matching
  // TODO: Guarantee that tha string is valid, a.k.a, NULL-terminated
  int count = 0;
  const char *pos = s;
  while(true) {
    pos = strstr(pos, " server ");
    if(pos!=NULL) count++;
    else break;
    pos += 6;
  }
  printf("HERE ARE %d SERVERS\n", count);
  return count;
}

struct conf_http *read_conf_file(const char *const path) {
  struct conf_http *http;
  char buf[BUF_SIZE];
  int fd = open(path, O_RDONLY);
  if(fd<0) {
    perror("open error");
    _exit(-1);
  }
  int len = read(fd, buf, BUF_SIZE);
  buf[len] = '\0';
  simplify(buf);
  parse(buf, &http);
  printf("++++++++++ in read_conf_file ++++++++++\n");
  // list_http(http);
  return http;
}

#ifndef FULL
int main() {
  char buf[BUF_SIZE];
  struct conf_http *http = read_conf_file("nginx.conf");
  // list_http(http);
  return 0;
}
#endif
